<?php
/**
 * User:chendenan
 * Created On 2022/3/19 0019 21:23
 */
namespace app\common\business;
use app\common\lib\Snowflake;
use app\common\model\mysql\{Order as OrderModel,OrderGoods as OrderGoodsModel};
use think\facade\Cache;

class Order extends BusBase{
    public $model = null;
    public function __construct(){
        $this->model = new OrderModel();
    }
    public function save($data){
        //拿到一个订单号
        $workId = rand(1, 1023);//随机数
        $orderId = Snowflake::getInstance()->setWorkId($workId)->id();
        //获取购物车数据
        $cartObj = new Cart();
        $result = $cartObj->lists($data['user_id'],$data['ids']);
        if(!$result){
            return false;
        }
        /*组装order_goods表数据*/
        $newResult = array_map(function($v) use ($orderId){
            $v['sku_id'] = $v['id'];
            unset($v['id']);
            $v['order_id'] = $orderId;
            return $v;
        },$result);
        /* 组装 goods_sku库存表数据  */
        //提交订单的 goods_sku 库存数据
        $resultSku = array_column($result,"num","id");
        //数据库中的 goods_sku 库存数据
        //$skuIds = array_column($result,"id");
        $skuIds = array_keys($resultSku);
        $goodsSku =(new GoodsSku())->getInIds($skuIds);
        $goodsSku = array_column($goodsSku,"stock","id");
        foreach ($goodsSku as $key => $value){
            $v['id'] = $key;
            $v['stock'] = $goodsSku[$key]-$resultSku[$key];
            $goodsSkuData[] = $v;
        }

        /* 组装goods库存数据 */
        foreach($result as $k => $v){
            if(isset($resultGoods[$v['goods_id']])){
                $resultGoods[$v['goods_id']]+= $v['num'];
            }else{
                $resultGoods[$v['goods_id']] = $v['num'];
            }
        }
        $goodsIds = array_keys($resultGoods);
        $goods = (new Goods())->getInIds($goodsIds);
        $resultGoodsStock = array_column($goods,"stock","id");
        foreach($resultGoodsStock as $k=>$v){
            $goodsStockData[$k]['id'] = $k;
            $goodsStockData[$k]['stock'] = $v - $resultGoods[$k];
        }
        /* 组装order订单表数据 */
        $price = array_sum(array_column($result,"total_price"));
        $orderData = [
            "user_id" => $data["user_id"],
            "order_id" => $orderId,
            "total_price" => $price,
            "address_id" => $data["address_id"],
        ];
        //使用事务
        $this->model->startTrans();
        try {
            //新增order表
            $id = $this->add($orderData);
            if(!$id){
                return 0;
            }
            //新增order_goods表
            $orderGoodsResult = (new OrderGoodsModel())->saveAll($newResult);
            //goods_sku表更新库存
            //$skuResult = (new GoodsSku())->updateStock($result); //单次循环更新
            $skuResult = (new GoodsSku())->updateAllStock($goodsSkuData);//saveAll 批量更新
            //goods表更新库存
            //$goodsResult = (new Goods())->updateStock($goodsStockData);
            $goodsResult = (new Goods())->updateAllStock($goodsStockData);
            //删除购物车里面添加的商品
            $cartObj->deleteRedis($data['user_id'],$data['ids']);
            //提交事务
            $this->model->commit();
            //把当前订单 ID 放入到延迟队列中，定期检测订单是否已经支付（因为订单有效期是20分钟，超过这个时间还没有支付
            //我们需要把这个订单取消，然后库存 + 操作）
            //延迟队列同样可以用在发货提醒、账号注册2分钟后发邮件等等；
            try {
                Cache::zAdd(config("redis.order_status_key"),time()+config("redis.order_expire"),$orderId);
            } catch (\Exception $e) {
                //记录日志 ，添加监控 ， 异步根据监控内容处理
                trace($e->getMessage(),"error");
            }

            return ["id"=>$orderId];
        } catch (\Exception $e){
            trace($e->getMessage(),"error");
            //回滚事务
            $this->model->rollback();
            return false;
        }
    }

    /**
     * 获取订单详情
     * @param $data
     * @return array|mixed
     */
    public function detail($data){
        //user_id 订单ID组合查询
        $condition = [
            "user_id" => $data['user_id'],
            "order_id" => $data['order_id'],
        ];
        try {
            $orders = $this->model->getByCondition($condition);
        } catch (\Exception $e) {
            $orders = [];
        }
        if(!($orders)) {
            return [];
        }
        $orders =  $orders->toArray();
        $orders = !empty($orders) ? $orders[0] : [];
        if(empty($orders)){
            return [];
        }
        $orders['id'] = $orders['order_id'];
        // 预留 地址查询，由于没做 先默认一个
        $orders['consignee_info'] = "江苏省 南京市 东信路 xxx";
//        $orders['mall_title'] = "111";
//        $orders['price'] = $orders['total_price'];
        //根据order_id查询 order_goods表信息数据
        $orderGoods = (new OrderGoods())->getByOrderId($data['order_id']);
        $orders['malls'] = $orderGoods;
        return $orders;
    }

    /**
     * 订单延迟队列 超时删除
     * @return bool
     */
    public function checkOrderStatus(){
        //检查是否有超时订单
        $result = Cache::store('redis')->zRangeByScore(config("redis.order_status_key"),0,time(),['limit' => [0,1]]);
        if(empty($result) || empty($result[0])) {
            return false;
        }
        try {
            //有的话删除
            $delRedis = Cache::store('redis')->zRem(config("redis.order_status_key"), $result[0]);
        } catch (\Exception $e) {
            //记录日志
            trace($e->getMessage(), "error");
            $delRedis = 0;
        }
        if($delRedis){
            echo "订单ID：{$result[0]}在规定时间内没有完成支付，我们判定为无效订单进行删除" . PHP_EOL;
            $this->model->startTrans();
            try {
                /**
                 * 第一步：根据订单ID去数据库order表里面获取当前这个订单数据，看下当前状态是否是待支付:status = 1
                 *      如果是待支付，那么我们需要把状态更新为 已取消 status = 7,否则不需要care
                 */
                $orderResult = $this->model->getByCondition(["order_id" => $result[0]]);
                $orderArr = $orderResult->toArray();
                if ($orderArr[0]['status'] == 1) {
                    $orderRes = $this->model->updateById($orderArr[0]['id'], ['status' => 7]);
                }
                /**
                 * 第二部：如果第一步status修改为7之后， 我们需要在查询order_goods表，拿到sku_id num 把goods_sku表数据库存增加 num
                 *      goods表总库存也需要修改。
                 */
                if ($orderRes) {
                    $orderGoodsResult = (new OrderGoodsModel())->getByCondition(["order_id" => $result[0]]);
                    $orderGoodsArr = $orderGoodsResult->toArray();
                    /*组装order_goods表数据*/
                    /* 组装goods库存数据 */
                    foreach ($orderGoodsArr as $k => $v) {
                        //组合order_goods数据[[sku_id1=>num],[sku_id2=>num]]
                        $goodsSkuData[$v['sku_id']] = $v['num'];
                        //组合goods数据成[[goods_id1=>num],[goods_id2=>num]]
                        if (isset($resultGoods[$v['goods_id']])) {
                            $resultGoods[$v['goods_id']] += $v['num'];
                        } else {
                            $resultGoods[$v['goods_id']] = $v['num'];
                        }
                    }
                    /* 组装goods_sku库存数据 */
                    $goodsSkuIds = array_keys($goodsSkuData);
                    $goodsSku = (new GoodsSku())->getInIds($goodsSkuIds);
                    $resultGoodsSkuStock = array_column($goodsSku, "stock", "id");
                    foreach ($resultGoodsSkuStock as $k1 => $v1) {
                        $goodsSkuStockData[$k1]['id'] = $k1;
                        $goodsSkuStockData[$k1]['stock'] = $v1 + $goodsSkuData[$k1];
                    }
                    /* 组装goods库存数据 */
                    $goodsIds = array_keys($resultGoods);
                    $goods = (new Goods())->getInIds($goodsIds);
                    $resultGoodsStock = array_column($goods, "stock", "id");
                    foreach ($resultGoodsStock as $k => $v) {
                        $goodsStockData[$k]['id'] = $k;
                        $goodsStockData[$k]['stock'] = $v + $resultGoods[$k];
                    }
                    //order_goods表更新库存
                    $GoodsSkuResult = (new GoodsSku())->updateAllStock($goodsSkuStockData);
                    //goods表更新库存
                    $goodsResult = (new Goods())->updateAllStock($goodsStockData);
                }
                $this->model->commit();
                return true;
            } catch (\Exception $e){
                trace($e->getMessage(),"error");
                $this->model->rollback();
                return false;
            }
        } else {
            return false;
        }

        return true;
    }
}